home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / UUCICO / dcpgpkt.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  61KB  |  1,718 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       d c p g p k t . c                                            */
  3. /*                                                                    */
  4. /*       UUCP 'g' protocol module for UUPC/extended.  Supports 7      */
  5. /*       window variable length packets of up yo 512 bytes in         */
  6. /*       length.                                                      */
  7. /*--------------------------------------------------------------------*/
  8.  
  9. /*--------------------------------------------------------------------*/
  10. /*       Stuart Lynne May/87                                          */
  11. /*                                                                    */
  12. /*       Copyright (c) Richard H. Lamb 1985, 1986, 1987               */
  13. /*       Changes Copyright (c) Stuart Lynne 1987                      */
  14. /*                                                                    */
  15. /*    Changes Copyright (c) 1989-1993 by Kendra Electronic            */
  16. /*    Wonderworks.                                                    */
  17. /*                                                                    */
  18. /*    All rights reserved except those explicitly granted by the      */
  19. /*    UUPC/extended license agreement.                                */
  20. /*--------------------------------------------------------------------*/
  21.  
  22. /*--------------------------------------------------------------------*/
  23. /*                          RCS Information                           */
  24. /*--------------------------------------------------------------------*/
  25.  
  26. /*
  27.  *      $Id: dcpgpkt.c 1.18 1993/10/04 03:57:20 ahd Exp $
  28.  *
  29.  *      $Log: dcpgpkt.c $
  30.  * Revision 1.18  1993/10/04  03:57:20  ahd
  31.  * Drop new lines from start up message
  32.  *
  33.  * Revision 1.17  1993/10/02  22:56:59  ahd
  34.  * Suppress compile warning
  35.  *
  36.  * Revision 1.16  1993/10/02  19:07:49  ahd
  37.  * Treat Windows 3.x ala DOS in handling packets in far memory
  38.  *
  39.  * Revision 1.15  1993/09/20  04:41:54  ahd
  40.  * OS/2 2.x support
  41.  *
  42.  * Revision 1.14  1993/07/22  23:22:27  ahd
  43.  * First pass at changes for Robert Denny's Windows 3.1 support
  44.  *
  45.  * Revision 1.13  1993/05/30  00:01:47  ahd
  46.  * Move UUFAR into header file
  47.  *
  48.  * Revision 1.12  1993/04/13  03:19:45  ahd
  49.  * Only perform copy to gspkt if input to gsendpkt is non-null
  50.  *
  51.  * Revision 1.11  1993/04/13  03:00:05  ahd
  52.  * Correct gspkt declare
  53.  *
  54.  * Revision 1.10  1993/04/13  02:26:30  ahd
  55.  * Move buffers to FAR memory
  56.  *
  57.  * Revision 1.9  1993/04/05  04:32:19  ahd
  58.  * Allow unique send and receive packet sizes
  59.  *
  60.  * Revision 1.8  1993/03/06  23:04:54  ahd
  61.  * Make state names more descriptive
  62.  *
  63.  * Revision 1.7  1992/11/21  05:55:11  ahd
  64.  * Use single bit field for gopenpk flag bits, add debugging info
  65.  *
  66.  * Revision 1.6  1992/11/20  12:38:39  ahd
  67.  * Add additional flags to avoid prematurely ending init sequence
  68.  *
  69.  * Revision 1.5  1992/11/19  03:00:29  ahd
  70.  * drop rcsid
  71.  *
  72.  * Revision 1.4  1992/11/17  13:45:37  ahd
  73.  * Add comments from Ian Talyor
  74.  *
  75.  * Revision 1.3  1992/11/16  02:10:27  ahd
  76.  * Rewrite protocol initialize to insure full exchange of packets
  77.  *
  78.  *          25Aug87 - Allow for up to 7 windows - Jal
  79.  *
  80.  *          01Nov87 - those strncpy's should really be memcpy's! -
  81.  *                    Jal
  82.  *
  83.  *          11Sep89 - Raise TimeOut to 15 - ahd
  84.  *
  85.  *          30Apr90 - Add Jordon Brown's fix for short packet
  86.  *                    retries. Reduce retry limit to 20
  87.  *
  88.  *          22Jul90 - Change error retry limit from per host to per
  89.  *                    packet.
  90.  *
  91.  *          22Jul90 - Add error message for number of retries
  92.  *                    exceeded
  93.  *
  94.  *          08Sep90 - Drop memmove to memcpy change supplied by
  95.  *                    Jordan Brown, MS 6.0 and Turbo C++ agree
  96.  *                    memmove insures no overlap
  97.  */
  98.  
  99. /*--------------------------------------------------------------------*/
  100. /*    Thanks goes to John Gilmore for sending me a copy of Greg       */
  101. /*    Chesson's UUCP protocol description -- Obviously invaluable.    */
  102. /*    Thanks also go to Andrew Tannenbaum for the section on          */
  103. /*    Siding window protocols with a program example in his           */
  104. /*    "Computer Networks" book.                                       */
  105. /*--------------------------------------------------------------------*/
  106.  
  107. /*--------------------------------------------------------------------*/
  108. /*                        System include files                        */
  109. /*--------------------------------------------------------------------*/
  110.  
  111. #include <stdio.h>
  112. #include <string.h>
  113. #include <time.h>
  114. #include <stdlib.h>
  115. #include <ctype.h>
  116.  
  117. #ifdef __TURBOC__
  118. #include <mem.h>
  119. #include <alloc.h>
  120. #else
  121. #include <malloc.h>
  122. #endif
  123.  
  124. /*--------------------------------------------------------------------*/
  125. /*                    UUPC/extended include files                     */
  126. /*--------------------------------------------------------------------*/
  127.  
  128. #include "lib.h"
  129. #include "dcp.h"
  130. #include "dcpsys.h"
  131. #include "dcpgpkt.h"
  132. #include "hostable.h"
  133. #include "security.h"
  134. #include "commlib.h"
  135. #include "modem.h"
  136. #include "catcher.h"
  137.  
  138. /*--------------------------------------------------------------------*/
  139. /*                           Local defines                            */
  140. /*--------------------------------------------------------------------*/
  141.  
  142. #define PKTSIZE   MAXPACK
  143. #define MINPKT    32
  144.  
  145. #define HDRSIZE   6
  146. #define MAXTRY 4
  147.  
  148. #ifndef GDEBUG
  149. #define GDEBUG 4
  150. #endif
  151.  
  152. #ifdef __OS2__
  153. #pragma warn -sig
  154. #endif
  155.  
  156. /*--------------------------------------------------------------------*/
  157. /*    Control whether some buffers are placed outside the default     */
  158. /*    data segment                                                    */
  159. /*--------------------------------------------------------------------*/
  160.  
  161. #ifdef __TURBOC__
  162. #define memavail  coreleft
  163. #else
  164. #define memavail  stackavail
  165. #endif
  166.  
  167. /*--------------------------------------------------------------------*/
  168. /*                     g-packet type definitions                      */
  169. /*--------------------------------------------------------------------*/
  170.  
  171. #define DATA   0
  172. #define CLOSE  1
  173. #define NAK    2
  174. #define SRJ    3
  175. #define ACK    4
  176. #define INITC  5
  177. #define INITB  6
  178. #define INITA  7
  179.  
  180. #define POK    -1
  181.  
  182. #define MAXWINDOW 7
  183. #define NBUF   8              /* always SAME as MAXSEQ ? */
  184. #define MAXSEQ 8
  185.  
  186. typedef enum {
  187.       I_EMPTY,
  188.       I_ERROR,
  189.       I_RESTART,
  190.       I_CALLEE,
  191.       I_CALLER,
  192.       I_GRPACK,
  193.       I_INITA_RECV,
  194.       I_INITA_SEND,
  195.       I_INITB_RECV,
  196.       I_INITB_SEND,
  197.       I_INITC_RECV,
  198.       I_INITC_SEND,
  199.       I_COMPLETE
  200.       } I_STATE;
  201.  
  202. #define between(a,b,c) ((a<=b && b<c) || \
  203.                         (c<a && a<=b) || \
  204.                         (b<c && c<a))
  205.  
  206. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  207. #define nextbuf(x)    ((x + 1) % (nwindows+1))
  208.  
  209. /*--------------------------------------------------------------------*/
  210. /*                 Handle 16 bit vs. 32 bit compilers                 */
  211. /*--------------------------------------------------------------------*/
  212.  
  213. #if defined(BIT32ENV)
  214. #define MEMSET(p,c,l)  memset(p,c,l)
  215. #define MEMCPY(t,s,l)  memcpy(t,s,l)
  216. #define MEMMOVE(t,s,l) memmove(t,s,l)
  217. #else
  218. #define MEMSET(p,c,l)  _fmemset(p,c,l)
  219. #define MEMCPY(t,s,l)  _fmemcpy(t,s,l)
  220. #define MEMMOVE(t,s,l) _fmemmove(t,s,l)
  221. #endif
  222.  
  223. /*--------------------------------------------------------------------*/
  224. /*              Global variables for packet definitions               */
  225. /*--------------------------------------------------------------------*/
  226.  
  227. currentfile();
  228.  
  229. static short rwl, swl, swu, rwu, irec, lazynak;
  230. static unsigned short nbuffers;
  231. static short rbl, sbl, sbu;
  232. static KEWSHORT nerr;
  233. static unsigned short outlen[NBUF], inlen[NBUF], xmitlen[NBUF];
  234. static boolean arrived[NBUF];
  235. static size_t nwindows;
  236.  
  237. static char UUFAR outbuf[NBUF][MAXPACK];
  238. static char UUFAR inbuf[NBUF][MAXPACK];
  239. static time_t ftimer[NBUF];
  240. static short timeouts, outsequence, naksin, naksout, screwups;
  241. static short reinit, shifts, badhdr, resends;
  242. static unsigned char *grpkt = NULL;
  243.  
  244. #if !defined(BIT32ENV)
  245. static char *gspkt = NULL;       // Local buffer dir
  246. #endif
  247.  
  248. static boolean variablepacket;  /* "v" or in modem file              */
  249.  
  250. /*--------------------------------------------------------------------*/
  251. /*                    Internal function prototypes                    */
  252. /*--------------------------------------------------------------------*/
  253.  
  254. static short initialize(const boolean caller, const char protocol );
  255.  
  256. static short  gmachine(const short timeout);
  257.  
  258. static void gspack(short  type,
  259.                    short  yyy,
  260.                    short  xxx,
  261.                    short  len,
  262.                    unsigned short xmit,
  263.                    char UUFAR *data);
  264.  
  265. static short  grpack(short  *yyy,
  266.                    short  *xxx,
  267.                    short  *len,
  268.                    char UUFAR *data,
  269.                    const short timeout);
  270.  
  271. static void gstats( void );
  272.  
  273. static unsigned short checksum(char *data, short len);
  274.  
  275. /****************** SUB SUB SUB PACKET HANDLER ************/
  276.  
  277. /*--------------------------------------------------------------------*/
  278. /*    g o p e n p k                                                   */
  279. /*                                                                    */
  280. /*    Initialize processing for protocol                              */
  281. /*--------------------------------------------------------------------*/
  282.  
  283. short Gopenpk(const boolean caller)
  284. {
  285.    return initialize(caller , 'G');
  286. } /* Gopenpk */
  287.  
  288. /*--------------------------------------------------------------------*/
  289. /*    v o p e n p k                                                   */
  290. /*                                                                    */
  291. /*    Initialize processing for protocol                              */
  292. /*--------------------------------------------------------------------*/
  293.  
  294. short vopenpk(const boolean caller)
  295. {
  296.    return initialize(caller, 'v');
  297. } /* vopenpk */
  298.  
  299. /*--------------------------------------------------------------------*/
  300. /*    g o p e n p k                                                   */
  301. /*                                                                    */
  302. /*    Initialize processing for protocol                              */
  303. /*--------------------------------------------------------------------*/
  304.  
  305. short gopenpk(const boolean caller)
  306. {
  307.    return initialize(caller, 'g');
  308. } /* vopenpk */
  309.  
  310. /*--------------------------------------------------------------------*/
  311. /*    i n i t i a l i z e                                             */
  312. /*                                                                    */
  313. /*    Initialize processing for protocol                              */
  314. /*--------------------------------------------------------------------*/
  315.  
  316. static short initialize(const boolean caller, const char protocol )
  317. {
  318.    short i, xxx, yyy, len, maxwindows;
  319.  
  320. #define B_SENT_INITA 0x01
  321. #define B_SENT_INITB 0x02
  322. #define B_SENT_INITC 0x04
  323. #define B_RECV_INITA 0x10
  324. #define B_RECV_INITB 0x20
  325. #define B_RECV_INITC 0x40
  326. #define B_INITA (B_SENT_INITA | B_RECV_INITA)
  327. #define B_INITB (B_SENT_INITB | B_RECV_INITB)
  328. #define B_INITC (B_SENT_INITC | B_RECV_INITC)
  329.  
  330.    short  flags = 0x00;   /* Init state flags, as defined above  */
  331.  
  332.    I_STATE state;
  333.  
  334. /*--------------------------------------------------------------------*/
  335. /*    Read modem file values for the number of windows and packet     */
  336. /*    sizes                                                           */
  337. /*--------------------------------------------------------------------*/
  338.  
  339.    r_pktsize = s_pktsize = GetGPacket( MAXPACK, protocol );
  340.    maxwindows = GetGWindow(
  341.                      min( MAXWINDOW, RECV_BUF / (s_pktsize+HDRSIZE)),
  342.                      protocol);
  343.  
  344.    variablepacket = bmodemflag[MODEM_VARIABLEPACKET] || (protocol == 'v');
  345.  
  346.    grpkt = malloc( r_pktsize + HDRSIZE );
  347.  
  348. /*--------------------------------------------------------------------*/
  349. /*                     Initialize error counters                      */
  350. /*--------------------------------------------------------------------*/
  351.  
  352.    timeouts = outsequence = naksin = naksout = screwups =
  353.       shifts = badhdr = resends = reinit = 0;
  354.  
  355. /*--------------------------------------------------------------------*/
  356. /*                    Initialize proto parameters                     */
  357. /*--------------------------------------------------------------------*/
  358.  
  359.    nerr = nbuffers = 0;
  360.    sbl = swl = swu = sbu = 1;
  361.    rbl = rwl = 0;
  362.    nwindows = maxwindows;
  363.    rwu = nwindows - 1;
  364.  
  365.    for (i = 0; i < NBUF; i++)
  366.    {
  367.       ftimer[i] = 0;
  368.       arrived[i] = FALSE;
  369.    }
  370.  
  371. /*--------------------------------------------------------------------*/
  372. /*                          3-way handshake                           */
  373. /*--------------------------------------------------------------------*/
  374.  
  375. /*--------------------------------------------------------------------*/
  376. /*    The three-way handshake should be independent of who            */
  377. /*    initializes it, but it seems that some versions of uucico       */
  378. /*    assume that the caller sends first and the callee responds.     */
  379. /*    This only matters if we are the callee and the first packet     */
  380. /*    is garbled.  If we send a packet, the other side will assume    */
  381. /*    that we must have seen the packet they sent and will never      */
  382. /*    time out and send it again.  Therefore, if we are the callee    */
  383. /*    we don't send a packet the first time through the loop.         */
  384. /*    This can still fail, but should usually work, and, after        */
  385. /*    all, if the initialization packets are received correctly       */
  386. /*    there will be no problem no matter what we do.                  */
  387. /*                                                                    */
  388. /*    (The above quoted verbatim from Ian Taylor)                     */
  389. /*--------------------------------------------------------------------*/
  390.  
  391.    state = caller ? I_CALLER : I_CALLEE;
  392.  
  393. /*--------------------------------------------------------------------*/
  394. /*    Exchange initialization messages with the other system.         */
  395. /*                                                                    */
  396. /*    A problem:                                                      */
  397. /*                                                                    */
  398. /*    We send INITA; it gets received                                 */
  399. /*    We receive INITA                                                */
  400. /*    We send INITB; it gets garbled                                  */
  401. /*    We receive INITB                                                */
  402. /*                                                                    */
  403. /*    We have seen and sent INITB, so we start to send INITC.  The    */
  404. /*    other side as sent INITB but not seen it, so it times out       */
  405. /*    and resends INITB.  We will continue sending INITC and the      */
  406. /*    other side will continue sending INITB until both sides give    */
  407. /*    up and start again with INITA.                                  */
  408. /*                                                                    */
  409. /*    It might seem as though if we are sending INITC and receive     */
  410. /*    INITB, we should resend our INITB, but this could cause         */
  411. /*    infinite echoing of INITB on a long-latency line.  Rather       */
  412. /*    than risk that, I have implemented a fast drop-back             */
  413. /*    procedure.  If we are sending INITB and receive INITC, the      */
  414. /*    other side has gotten ahead of us.  We immediately fail and     */
  415. /*    begin again with INITA.  For the other side, if we are          */
  416. /*    sending INITC and see INITA, we also immediately fail back      */
  417. /*    to INITA.                                                       */
  418. /*                                                                    */
  419. /*    Unfortunately, this doesn't work for the other case, in         */
  420. /*    which we are sending INITB but the other side has not yet       */
  421. /*    seen INITA.  As far as I can see, if this happens we just       */
  422. /*    have to wait until we time out and resend INITA.                */
  423. /*                                                                    */
  424. /*    (The above also quoted verbatim from Ian Taylor; however, the   */
  425. /*    code and associated bugs are all Drew's)                        */
  426. /*--------------------------------------------------------------------*/
  427.  
  428. /*--------------------------------------------------------------------*/
  429. /*    A note about the games with the variable "flags", which is      */
  430. /*    bit twiddled alot below.  The statement below:                  */
  431. /*                                                                    */
  432. /*          flags = (flags & B_SENT_INITA) | B_RECV_INITA;            */
  433. /*                                                                    */
  434. /*    works to turn off all the bits in flags except B_SENT_INITA     */
  435. /*    if it was already on, and then turns on flag B_RECV_INITA.      */
  436. /*    We use statements like this to reset most of the flags at       */
  437. /*    once, leaving one or two bits on; this in turn allows us to     */
  438. /*    check in later states that the previous two states were the     */
  439. /*    expected ones.                                                  */
  440. /*                                                                    */
  441. /*    Likewise, the following statement:                              */
  442. /*                                                                    */
  443. /*          state = (flags & B_SENT_INITA) ?                          */
  444. /*                         I_INITB_SEND : I_INITA_SEND;               */
  445. /*                                                                    */
  446. /*    tests to see if B_SENT_INITA was already set, and return the    */
  447. /*    "true" condition (I_INITB_SEND) otherwise return the "false"    */
  448. /*    (I_INITA_SEND).                                                 */
  449. /*--------------------------------------------------------------------*/
  450.  
  451.  
  452.    while( state != I_COMPLETE )
  453.    {
  454.       printmsg(4, "gopenpk: I State = %2d, flag = 0x%02x",
  455.                (int) state, (int) flags);
  456.  
  457.       switch( state )
  458.       {
  459.  
  460. /*--------------------------------------------------------------------*/
  461. /*                          Receive a packet                          */
  462. /*--------------------------------------------------------------------*/
  463.  
  464.          case I_GRPACK:
  465.             switch (grpack(&yyy, &xxx, &len, NULL, M_gPacketTimeout ))
  466.             {
  467.  
  468.                case INITA:
  469.                   printmsg(5, "**got INITA");
  470.                   state = I_INITA_RECV;
  471.                   break;
  472.  
  473.                case INITB:
  474.                   printmsg(5, "**got INITB");
  475.                   state = I_INITB_RECV;
  476.                   break;
  477.  
  478.                case INITC:
  479.                   printmsg(5, "**got INITC");
  480.                   state = I_INITC_RECV;
  481.                   break;
  482.  
  483.                case DCP_EMPTY:
  484.                   printmsg(GDEBUG, "**got EMPTY");
  485.                   state = I_EMPTY;
  486.  
  487.                   if (bmodemflag[MODEM_CD] && !CD())
  488.                   {
  489.                      printmsg(0,"gopenpk: Modem carrier lost");
  490.                      return DCP_FAILED;
  491.                   }
  492.                   break;
  493.  
  494.                case CLOSE:
  495.                   printmsg(GDEBUG, "**got CLOSE");
  496.                   gspack(CLOSE, 0, 0, 0, 0, NULL);
  497.                   return DCP_FAILED;
  498.  
  499.                default:
  500.                   printmsg(GDEBUG, "**got SCREW UP");
  501.                   state = I_ERROR;
  502.                   break;
  503.             }
  504.  
  505.             if (bmodemflag[MODEM_CD] && !CD())
  506.             {
  507.                printmsg(0,"gopenpk: Modem carrier lost");
  508.                return DCP_FAILED;
  509.             }
  510.             break;
  511.  
  512. /*--------------------------------------------------------------------*/
  513. /*                         Initialize states                          */
  514. /*--------------------------------------------------------------------*/
  515.  
  516.          case I_CALLER:
  517.             state = I_INITA_SEND;
  518.             break;
  519.  
  520.          case I_CALLEE:
  521.             state = I_GRPACK;
  522.             break;
  523.  
  524. /*--------------------------------------------------------------------*/
  525. /*                  Process received or sent packets                  */
  526. /*--------------------------------------------------------------------*/
  527.  
  528.          case I_INITA_RECV:
  529.             if (yyy < (short) nwindows)
  530.             {
  531.                nwindows = yyy;
  532.                rwu = nwindows - 1;
  533.             }
  534.             flags = (flags & B_SENT_INITA) | B_RECV_INITA;
  535.             state = (flags & B_SENT_INITA) ? I_INITB_SEND : I_INITA_SEND;
  536.             break;
  537.  
  538.          case I_INITA_SEND:
  539.             gspack(INITA, 0, 0, 0, nwindows, NULL);
  540.             flags = (flags & B_RECV_INITA) | B_SENT_INITA;
  541.             state = I_GRPACK;
  542.             break;
  543.  
  544.          case I_INITB_RECV:
  545.             if ((flags & (B_RECV_INITA | B_SENT_INITA)) ==
  546.                          (B_RECV_INITA | B_SENT_INITA))
  547.             {
  548.                i = (short) 8 * (2 << (yyy+1));
  549.                if (i < (short) s_pktsize)
  550.                   s_pktsize = i;
  551.                flags = (flags & B_SENT_INITB) | B_RECV_INITB;
  552.                state = (flags & B_SENT_INITB) ? I_INITC_SEND : I_INITB_SEND;
  553.             } /* if */
  554.             else
  555.                state = I_RESTART;
  556.             break;
  557.  
  558.          case I_INITB_SEND:
  559.             gspack(INITB, 0, 0, 0, r_pktsize, NULL);
  560.                                        /* Data segment (packet) size    */
  561.             flags = (flags & (B_INITA | B_RECV_INITB)) | B_SENT_INITB;
  562.             state = I_GRPACK;
  563.             break;
  564.  
  565.          case I_INITC_RECV:
  566.             if ((flags & (B_RECV_INITB | B_SENT_INITB)) ==
  567.                            (B_RECV_INITB | B_SENT_INITB))
  568.             {
  569.                if (yyy < (short) nwindows)
  570.                {
  571.                   printmsg(0,"Unexpected INITC window size of %d",
  572.                              nwindows );
  573.                   nwindows = yyy;
  574.                   rwu = nwindows - 1;
  575.                }
  576.                flags = (flags & B_SENT_INITC) | B_RECV_INITC;
  577.                state = (flags & B_SENT_INITC) ? I_COMPLETE : I_INITC_SEND;
  578.             }
  579.             else
  580.                state = I_RESTART;
  581.             break;
  582.  
  583.          case I_INITC_SEND:
  584.             gspack(INITC, 0, 0, 0, nwindows, NULL);
  585.             flags = (flags & (B_INITB | B_RECV_INITC)) | B_SENT_INITC;
  586.             state = (flags & B_RECV_INITC) ? I_COMPLETE : I_GRPACK;
  587.             break;
  588.  
  589. /*--------------------------------------------------------------------*/
  590. /*                            Error states                            */
  591. /*--------------------------------------------------------------------*/
  592.  
  593.          case I_EMPTY:
  594.             timeouts++;
  595.             state = I_RESTART;
  596.             break;
  597.  
  598.          case I_ERROR:
  599.             screwups++;
  600.             state = I_RESTART;
  601.             break;
  602.  
  603.          case I_RESTART:
  604.             printmsg(2,"gopenpk: Restarting initialize sequence");
  605.             nerr++;
  606.             flags = 0x00;
  607.             state = I_INITA_SEND;
  608.             break;
  609.  
  610.       } /* switch */
  611.  
  612.       if ( terminate_processing )
  613.       {
  614.          printmsg(0,"gopenpk: Terminated by user");
  615.          return DCP_FAILED;
  616.       }
  617.  
  618.       if (nerr >= M_MaxErr)
  619.       {
  620.          remote_stats.errors += nerr;
  621.          nerr = 0;
  622.          printmsg(0,
  623.             "gopenpk: Consecutive error limit of %ld exceeded, "
  624.                      "%ld total errors",
  625.              (long) M_MaxErr, remote_stats.errors);
  626.          return(DCP_FAILED);
  627.       }
  628.    } /* while */
  629.  
  630. /*--------------------------------------------------------------------*/
  631. /*                    Allocate the needed buffers                     */
  632. /*--------------------------------------------------------------------*/
  633.  
  634.    grpkt = realloc( grpkt, r_pktsize + HDRSIZE );
  635.    checkref( grpkt );
  636.  
  637. #if !defined(BIT32ENV)
  638.    gspkt = malloc( s_pktsize );
  639.    checkref( gspkt );
  640. #endif
  641.  
  642.    nerr = 0;
  643.    lazynak = 0;
  644.  
  645.  
  646. #if defined(BIT32ENV) || defined(_Windows)
  647.    printmsg(2,"%s packets, "
  648.               "Window size %d, "
  649.               "Receive packet %d, "
  650.               "Send packet %d",
  651.             variablepacket ? "Variable" : "Fixed",
  652.             nwindows,
  653.             r_pktsize,
  654.             s_pktsize );
  655. #else
  656.    printmsg(2,"%s packets, "
  657.               "Window size %d, "
  658.               "Receive packet %d, "
  659.               "Send packet %d, "
  660.               "Memory avail %u",
  661.             variablepacket ? "Variable" : "Fixed",
  662.             nwindows,
  663.             r_pktsize,
  664.             s_pktsize,
  665.             memavail());
  666. #endif
  667.  
  668.    return(DCP_OK); /* channel open */
  669.  
  670. } /*initialize*/
  671.  
  672. /*--------------------------------------------------------------------*/
  673. /*    g f i l e p k t                                                 */
  674. /*                                                                    */
  675. /*    Begin a file transfer (not used by "g" protocol)                */
  676. /*--------------------------------------------------------------------*/
  677.  
  678. short gfilepkt( void )
  679. {
  680.  
  681.    return DCP_OK;
  682.  
  683. } /* gfilepkt */
  684.  
  685. /*--------------------------------------------------------------------*/
  686. /*    g c l o s e p k                                                 */
  687. /*                                                                    */
  688. /*    Close packet machine                                            */
  689. /*--------------------------------------------------------------------*/
  690.  
  691. short gclosepk()
  692. {
  693.    unsigned short i;
  694.  
  695.    for (i = 0; i < MAXTRY; i++)
  696.    {
  697.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  698.       if (gmachine(M_gPacketTimeout) == CLOSE)
  699.          break;
  700.    } /* for (i = 0; i < MAXTRY; i++) */
  701.  
  702. /*--------------------------------------------------------------------*/
  703. /*                        Release our buffers                         */
  704. /*--------------------------------------------------------------------*/
  705.  
  706.    free( grpkt );
  707.    grpkt = NULL;
  708.  
  709. #if !defined(BIT32ENV)
  710.    free( gspkt );
  711.    gspkt = NULL;
  712. #endif
  713.  
  714. /*--------------------------------------------------------------------*/
  715. /*                Report the results of our adventures                */
  716. /*--------------------------------------------------------------------*/
  717.  
  718.    gstats();
  719.  
  720. /*--------------------------------------------------------------------*/
  721. /*                          Return to caller                          */
  722. /*--------------------------------------------------------------------*/
  723.  
  724.    return(0);
  725.  
  726. } /*gclosepk*/
  727.  
  728. /*--------------------------------------------------------------------*/
  729. /*    g s t a t s                                                     */
  730. /*                                                                    */
  731. /*    Report summary of errors for processing                         */
  732. /*--------------------------------------------------------------------*/
  733.  
  734. static void gstats( void )
  735. {
  736.    remote_stats.errors += nerr;
  737.    nerr = 0;
  738.    if ( remote_stats.errors || badhdr )
  739.    {
  740.       printmsg(0,
  741.          "%d time outs, %d port reinits, %d out of seq pkts, "
  742.          "%d NAKs rec, %d NAKs sent",
  743.             timeouts, reinit, outsequence, naksin, naksout);
  744.       printmsg(0,
  745.          "%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
  746.             screwups, shifts, badhdr, resends);
  747.    } /* if ( remote_stats.errors || shifts || badhdr ) */
  748. } /* gstats */
  749.  
  750. /*--------------------------------------------------------------------*/
  751. /*    g g e t p k t                                                   */
  752. /*                                                                    */
  753. /*    Gets no more than a packet's worth of data from                 */
  754. /*    the "packet I/O state machine".  May have to                    */
  755. /*    periodically run the packet machine to get some packets.        */
  756. /*                                                                    */
  757. /*    on input:   don't care                                          */
  758. /*    on return:  data+\0 and length in len.                          */
  759. /*                                                                    */
  760. /*    ret(0)   if all's well                                          */
  761. /*    ret(-1) if problems (failed)                                    */
  762. /*--------------------------------------------------------------------*/
  763.  
  764. short ggetpkt(char *data, short *len)
  765. {
  766.    short   retry = M_MaxErr;
  767.    time_t start;
  768. #ifdef _DEBUG
  769.    short savedebug = debuglevel;
  770. #endif
  771.  
  772.    irec = 1;
  773.    checkref( data );
  774.  
  775. /*--------------------------------------------------------------------*/
  776. /*                Loop to wait for the desired packet                 */
  777. /*--------------------------------------------------------------------*/
  778.  
  779.    time( &start );
  780.    while (!arrived[rbl] && retry)
  781.    {
  782.       if (gmachine(M_gPacketTimeout) != POK)
  783.          return(-1);
  784.  
  785.       if (!arrived[rbl] )
  786.       {
  787.          time_t now;
  788.          if (time( &now ) > (start + M_gPacketTimeout) )
  789.          {
  790. #ifdef _DEBUG
  791.             if ( debuglevel < 6 )
  792.                debuglevel = 6;
  793. #endif
  794.             printmsg(GDEBUG,
  795.                      "ggetpkt: Timeout %d waiting for inbound packet %d",
  796.                      M_MaxErr - --retry, remote_stats.packets + 1);
  797.             timeouts++;
  798.             start = now;
  799.          } /* if (time( now ) > (start + M_gPacketTimeout) ) */
  800.       } /* if (!arrived[rbl] ) */
  801.    } /* while (!arrived[rbl] && i) */
  802.  
  803. #ifdef _DEBUG
  804.    debuglevel = savedebug;
  805. #endif
  806.  
  807.    if (!arrived[rbl])
  808.    {
  809.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  810.                (long) M_gPacketTimeout * M_MaxErr);
  811.       gclosepk();
  812.       return -1;
  813.    }
  814.  
  815. /*--------------------------------------------------------------------*/
  816. /*                           Got a packet!                            */
  817. /*--------------------------------------------------------------------*/
  818.  
  819.    *len = inlen[rbl];
  820.    MEMCPY(data, inbuf[rbl], *len);
  821.  
  822.    arrived[rbl] = FALSE;      /* Buffer is now emptied               */
  823.    rwu = nextpkt(rwu);        /* bump receive window                 */
  824.  
  825.    return(0);
  826.  
  827. } /*ggetpkt*/
  828.  
  829.  
  830. /*
  831.    g s e n d p k t
  832.  
  833.    Put at most a packet's worth of data in the packet state
  834.    machine for transmission.
  835.    May have to run the packet machine a few times to get
  836.    an available output slot.
  837.  
  838.    on input: data=*data; len=length of data in data.
  839.  
  840.    return:
  841.     0 if all's well
  842.    -1 if problems (failed)
  843. */
  844.  
  845. short gsendpkt(char *data, short len)
  846. {
  847.    short delta;
  848. #ifdef _DEBUG
  849.    short savedebug = debuglevel;
  850. #endif
  851.  
  852.    checkref( data );
  853.    irec = 0;
  854.  
  855. /*--------------------------------------------------------------------*/
  856. /*       WAIT FOR INPUT i.e. if we have sent SWINDOW pkts and none    */
  857. /*       have been acked, wait for acks.  Note that we always go      */
  858. /*       through the machine at least once to keep caught up with     */
  859. /*       ACK's sent by remote machine.                                */
  860. /*--------------------------------------------------------------------*/
  861.  
  862.    do {
  863.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  864.          return(-1);
  865.    } while (nbuffers >= nwindows);
  866.  
  867. /*--------------------------------------------------------------------*/
  868. /*               Place packet in table and mark unacked               */
  869. /*--------------------------------------------------------------------*/
  870.  
  871.    MEMCPY(outbuf[sbu], data, len);
  872.  
  873. /*--------------------------------------------------------------------*/
  874. /*                       Handle short packets.                        */
  875. /*--------------------------------------------------------------------*/
  876.  
  877.    xmitlen[sbu] = s_pktsize;
  878.    if (variablepacket)
  879.       while ( ((len * 2) < (short) xmitlen[sbu]) && (xmitlen[sbu] > MINPKT) )
  880.          xmitlen[sbu] /= 2;
  881.  
  882.    if ( xmitlen[sbu] < MINPKT )
  883.    {
  884.       printmsg(0,"gsendpkt: Bad packet size %d, "
  885.                "data length %d",
  886.                xmitlen[sbu], len);
  887.       xmitlen[sbu] = MINPKT;
  888.    }
  889.  
  890.    delta = xmitlen[sbu] - len;
  891.    if (delta > 127)
  892.    {
  893.       MEMMOVE(outbuf[sbu] + 2, outbuf[sbu], len);
  894.       MEMSET(outbuf[sbu]+len+2, 0, delta - 2);
  895.                               /* Pad with nulls.  Ugh.               */
  896.       outbuf[sbu][0] = (unsigned char) ((delta & 0x7f) | 0x80);
  897.       outbuf[sbu][1] = (unsigned char) (delta >> 7);
  898.    } /* if (delta > 127) */
  899.    else if (delta > 0 )
  900.    {
  901.       MEMMOVE(outbuf[sbu] + 1, outbuf[sbu], len);
  902.       outbuf[sbu][0] = (unsigned char) delta;
  903.       MEMSET(outbuf[sbu]+len+1, 0, delta - 1);
  904.                               /* Pad with nulls.  Ugh.               */
  905.    } /* else if (delta > 0 )  */
  906.  
  907. /*--------------------------------------------------------------------*/
  908. /*                            Mark packet                             */
  909. /*--------------------------------------------------------------------*/
  910.  
  911.    outlen[sbu] = len;
  912.    ftimer[sbu] = time(nil(long));
  913.    nbuffers++;
  914.  
  915. /*--------------------------------------------------------------------*/
  916. /*                              send it                               */
  917. /*--------------------------------------------------------------------*/
  918.  
  919.    gspack(DATA, rwl, swu, outlen[sbu], xmitlen[sbu], outbuf[sbu]);
  920.  
  921.    swu = nextpkt(swu);        /* Bump send window                    */
  922.    sbu = nextbuf( sbu );      /* Bump to next send buffer            */
  923.  
  924. #ifdef _DEBUG
  925.    debuglevel = savedebug;
  926. #endif
  927.  
  928.    return(0);
  929.  
  930. } /*gsendpkt*/
  931.  
  932.  
  933. /*--------------------------------------------------------------------*/
  934. /*    g e o f p k t                                                   */
  935. /*                                                                    */
  936. /*    Transmit EOF to the other system                                */
  937. /*--------------------------------------------------------------------*/
  938.  
  939. short geofpkt( void )
  940. {
  941.    if ((*sendpkt)("", 0))          /* Empty packet == EOF              */
  942.       return DCP_FAILED;
  943.    else
  944.       return DCP_OK;
  945. } /* geofpkt */
  946.  
  947. /*--------------------------------------------------------------------*/
  948. /*    g w r m s g                                                     */
  949. /*                                                                    */
  950. /*    Send a message to remote system                                 */
  951. /*--------------------------------------------------------------------*/
  952.  
  953. short gwrmsg( char *s )
  954. {
  955.    for( ; strlen(s) >= s_pktsize; s += s_pktsize)
  956.    {
  957.       short result = (*sendpkt)(s, (short) s_pktsize);
  958.       if (result)
  959.          return result;
  960.    }
  961.  
  962.    return (*sendpkt)(s, (short) (strlen(s) + 1));
  963. } /* gwrmsg */
  964.  
  965. /*--------------------------------------------------------------------*/
  966. /*    g r d m s g                                                     */
  967. /*                                                                    */
  968. /*    Read a message from the remote system                           */
  969. /*--------------------------------------------------------------------*/
  970.  
  971. short grdmsg( char *s)
  972. {
  973.    for ( ;; )
  974.    {
  975.       short len;
  976.       short result = (*getpkt)( s, &len );
  977.       if (result || (s[len-1] == '\0'))
  978.          return result;
  979.       s += len;
  980.    } /* for */
  981.  
  982. } /* grdmsg */
  983.  
  984. /**********  Packet Machine  ********** RH Lamb 3/87 */
  985.  
  986. /*--------------------------------------------------------------------*/
  987. /*    g m a c h i n e                                                 */
  988. /*                                                                    */
  989. /*    Ideally we would like to fork this process off in an            */
  990. /*    infinite loop and send and receive packets through "inbuf"      */
  991. /*    and "outbuf".  Can't do this in MS-DOS so we setup "getpkt"     */
  992. /*    and "sendpkt" to call this routine often and return only        */
  993. /*    when the input buffer is empty thus "blocking" the packet-      */
  994. /*    machine task.                                                   */
  995. /*--------------------------------------------------------------------*/
  996.  
  997. static short gmachine(const short timeout )
  998. {
  999.    static time_t idletimer = 0;
  1000.  
  1001.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  1002.    boolean close  = FALSE;    /* True = terminate connection upon
  1003.                                         exit                      */
  1004.    boolean inseq  = TRUE;     /* True = Count next out of sequence
  1005.                                         packet as an error           */
  1006.    while ( !done )
  1007.    {
  1008.       boolean resend = FALSE;    /* True = resend data packets       */
  1009.       boolean donak  = FALSE;    /* True = NAK the other system      */
  1010.       unsigned long packet_no = remote_stats.packets;
  1011.  
  1012.       short pkttype, rack, rseq, rlen, rbuf, i1;
  1013.       time_t now;
  1014.  
  1015. #ifdef UDEBUG
  1016.       if ( debuglevel >= 7 )     /* Optimize processing a little bit */
  1017.       {
  1018.  
  1019.          printmsg(10, "* send %d %d < W < %d %d, "
  1020.                       "receive %d %d < W < %d, "
  1021.                       "error %d, packet %d",
  1022.             swl, sbl, swu, sbu, rwl, rbl, rwu, nerr,
  1023.             (long) remote_stats.packets);
  1024.  
  1025. /*--------------------------------------------------------------------*/
  1026. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  1027. /*    rwl=expected pkt                                                */
  1028. /*--------------------------------------------------------------------*/
  1029.  
  1030.       }
  1031. #endif
  1032.  
  1033. /*--------------------------------------------------------------------*/
  1034. /*             Attempt to retrieve a packet and handle it             */
  1035. /*--------------------------------------------------------------------*/
  1036.  
  1037.       pkttype = grpack(&rack, &rseq, &rlen, inbuf[nextbuf(rbl)], timeout);
  1038.       time(&now);
  1039.       switch (pkttype) {
  1040.  
  1041.          case CLOSE:
  1042.             remote_stats.packets++;
  1043.             printmsg(GDEBUG, "**got CLOSE");
  1044.             close = done = TRUE;
  1045.             break;
  1046.  
  1047.          case DCP_EMPTY:
  1048.             printmsg(timeout ? GDEBUG : 8, "**got EMPTY");
  1049.  
  1050.             if (bmodemflag[MODEM_CD] && !CD())
  1051.             {
  1052.                printmsg(0,"gmachine: Modem carrier lost");
  1053.                nerr++;
  1054.                close = TRUE;
  1055.             }
  1056.  
  1057.             if ( terminate_processing )
  1058.             {
  1059.                printmsg(0,"gmachine: User aborted processing");
  1060.                close = TRUE;
  1061.             }
  1062.  
  1063.             if (ftimer[sbl])
  1064.             {
  1065. #ifdef UDEBUG
  1066.                printmsg(6, "---> seq, elapst %d %ld", sbl,
  1067.                     ftimer[sbl] - now);
  1068. #endif
  1069.                if ( ftimer[sbl] <= (now - M_gPacketTimeout))
  1070.                {
  1071.                    printmsg(4, "*** timeout %d (%ld)",
  1072.                                sbl, (long) remote_stats.packets);
  1073.                        /* Since "g" is "go-back-N", when we time out we
  1074.                           must send the last N pkts in order.  The generalized
  1075.                           sliding window scheme relaxes this reqirment. */
  1076.                    nerr++;
  1077.                    timeouts++;
  1078.                    resend = TRUE;
  1079.                } /* if */
  1080.             } /* if */
  1081.  
  1082.             done = TRUE;
  1083.             break;
  1084.  
  1085.          case DATA:
  1086.             printmsg(5, "**got DATA %d %d", rack, rseq);
  1087.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  1088.             if (i1 == rseq) {
  1089.                lazynak--;
  1090.                remote_stats.packets++;
  1091.                idletimer = now;
  1092.                rwl = i1;
  1093.                rbl = nextbuf( rbl );
  1094.                inseq = arrived[rbl] = TRUE;
  1095.                inlen[rbl] = rlen;
  1096.                printmsg(5, "*** ACK d %d %d", rwl, rbl);
  1097.                gspack(ACK, rwl, 0, 0, 0, NULL);
  1098.                done = TRUE;   /* return to caller when finished      */
  1099.                               /* in a mtask system, unneccesary      */
  1100.             } else {
  1101.                if (inseq || ( now > (idletimer + M_gPacketTimeout)))
  1102.                {
  1103.                   donak = TRUE;  /* Only flag first out of sequence
  1104.                                     packet as error, since we know
  1105.                                     following ones also bad             */
  1106.                   outsequence++;
  1107.                   inseq = FALSE;
  1108.                }
  1109.                printmsg(GDEBUG, "*** unexpect %d ne %d (%d - %d)",
  1110.                                        rseq, i1, rwl, rwu);
  1111.             } /* else */
  1112.  
  1113.             if ( swl == swu )       /* We waiting for an ACK?     */
  1114.                break;               /* No --> Skip ACK processing */
  1115.             /* else Fall through to ACK case */
  1116.  
  1117.          case NAK:
  1118.          case ACK:
  1119.             if (pkttype == NAK)
  1120.             {
  1121.                nerr++;
  1122.                naksin++;
  1123.                printmsg(5, "**got NAK %d", rack);
  1124.                resend = TRUE;
  1125.             }
  1126.             else if (pkttype == ACK)
  1127.                printmsg(5, "**got ACK %d", rack);
  1128.  
  1129.             while(between(swl, rack, swu))
  1130.             {                             /* S<-- -->(S+W-1)%8 */
  1131.                remote_stats.packets++;
  1132.                printmsg(5, "*** ACK %d", swl);
  1133.                ftimer[sbl] = 0;
  1134.                idletimer = now;
  1135.                nbuffers--;
  1136.                done = TRUE;            /* Get more data for input */
  1137.                swl = nextpkt(swl);
  1138.                sbl = nextbuf(sbl);
  1139.             } /* while */
  1140.  
  1141.             if (!done && (pkttype == ACK)) /* Find packet?         */
  1142.             {
  1143.                printmsg(GDEBUG,"*** ACK for bad packet %d (%d - %d)",
  1144.                            rack, swl, swu);
  1145.             } /* if */
  1146.             break;
  1147.  
  1148.          case DCP_ERROR:
  1149.             printmsg(GDEBUG, "*** got BAD CHK");
  1150.             naksout++;
  1151.             donak = TRUE;
  1152.             lazynak = 0;               /* Always NAK bad checksum */
  1153.             break;
  1154.  
  1155.          default:
  1156.             screwups++;
  1157.             nerr++;
  1158.             printmsg(GDEBUG, "*** got SCREW UP");
  1159.             break;
  1160.  
  1161.       } /* switch */
  1162.  
  1163. /*--------------------------------------------------------------------*/
  1164. /*      If we received an NAK or timed out, resend data packets       */
  1165. /*--------------------------------------------------------------------*/
  1166.  
  1167.       if ( resend )
  1168.       for (rack = swl,
  1169.            rbuf = sbl;
  1170.            between(swl, rack, swu);
  1171.            rack = nextpkt(rack), rbuf = nextbuf( rbuf ))
  1172.       {                          /* resend rack->(swu-1)             */
  1173.          resends++;
  1174.  
  1175.          if ( outbuf[rbuf] == NULL )
  1176.          {
  1177.             printmsg(0,"gmachine: Transmit of NULL packet (%d %d)",
  1178.                      rwl, rbuf);
  1179.             panic();
  1180.          }
  1181.  
  1182.          if ( xmitlen[rbuf] == 0 )
  1183.          {
  1184.             printmsg(0,"gmachine: Transmit of 0 length packet (%d %d)",
  1185.                      rwl, rbuf);
  1186.             panic();
  1187.          }
  1188.  
  1189.          gspack(DATA, rwl, rack, outlen[rbuf], xmitlen[rbuf], outbuf[rbuf]);
  1190.          printmsg(5, "*** resent %d", rack);
  1191.          idletimer = ftimer[rbuf] = now;
  1192.       } /* for */
  1193.  
  1194. /*--------------------------------------------------------------------*/
  1195. /*  If we have an error and have not recently sent a NAK, do so now.  */
  1196. /*  We then reset our counter so we receive at least a window full of */
  1197. /*                 packets before sending another NAK                 */
  1198. /*--------------------------------------------------------------------*/
  1199.  
  1200.       if ( donak )
  1201.       {
  1202.          nerr++;
  1203.          if ( (lazynak < 1) || (now > (idletimer + M_gPacketTimeout)))
  1204.          {
  1205.             printmsg(5, "*** NAK d %d", rwl);
  1206.             gspack(NAK, rwl, 0, 0, 0, NULL);
  1207.             naksout++;
  1208.             idletimer = now;
  1209.             lazynak = nwindows + 1;
  1210.          } /* if ( lazynak < 1 ) */
  1211.       } /* if ( donak ) */
  1212.  
  1213. /*--------------------------------------------------------------------*/
  1214. /*                   Update error counter if needed                   */
  1215. /*--------------------------------------------------------------------*/
  1216.  
  1217.       if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
  1218.       {
  1219.          printmsg(GDEBUG,"gmachine: Packet %ld had %ld errors during transfer",
  1220.                      remote_stats.packets, (long) nerr);
  1221.          remote_stats.errors += nerr;
  1222.          nerr = 0;
  1223.       }
  1224.  
  1225. /*--------------------------------------------------------------------*/
  1226. /*    If we have an excessive number of errors, drop out of the       */
  1227. /*    loop                                                            */
  1228. /*--------------------------------------------------------------------*/
  1229.  
  1230.       if (nerr >= M_MaxErr)
  1231.       {
  1232.          printmsg(0,
  1233.             "gmachine: Consecutive error limit of %d exceeded, %d total errors",
  1234.             M_MaxErr, nerr + remote_stats.errors);
  1235.          done = close = TRUE;
  1236.          gstats();
  1237.       }
  1238.    } /* while */
  1239.  
  1240. /*--------------------------------------------------------------------*/
  1241. /*    Return to caller, gracefully terminating packet machine if      */
  1242. /*    requested                                                       */
  1243. /*--------------------------------------------------------------------*/
  1244.  
  1245.    if ( close )
  1246.    {
  1247.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  1248.       return CLOSE;
  1249.    }
  1250.    else
  1251.       return POK;
  1252.  
  1253. } /*gmachine*/
  1254.  
  1255.  
  1256. /*************** FRAMING *****************************/
  1257.  
  1258. /*
  1259.    g s p a c k
  1260.  
  1261.    Send a packet
  1262.  
  1263.    type=type yyy=pkrec xxx=timesent len=length<=s_pktsize data=*data
  1264.    ret(0) always
  1265. */
  1266.  
  1267. static void gspack(short type,
  1268.                    short yyy,
  1269.                    short xxx,
  1270.                    short len,
  1271.                    unsigned short xmit,
  1272. #if defined(BIT32ENV)
  1273.                    char *data)
  1274. #else
  1275.                    char UUFAR *input)
  1276. #endif
  1277. {
  1278.    unsigned short check, i;
  1279.    unsigned char header[HDRSIZE];
  1280.  
  1281. #if !defined(BIT32ENV)
  1282.    char *data;                   // Local data buffer address
  1283.    if ( input == NULL )
  1284.       data = NULL;               // Make consistent with real buffer
  1285.    else {                        // Only copy if non-NULL
  1286.       data = gspkt;
  1287.       MEMCPY( data, input, xmit );
  1288.    }
  1289. #endif
  1290.  
  1291. #ifdef   LINKTEST
  1292.    /***** Link Testing Mods *****/
  1293.    unsigned char dpkerr[10];
  1294.    /***** End Link Testing Mods *****/
  1295. #endif   /* LINKTEST */
  1296.  
  1297. #ifdef   LINKTEST
  1298.    /***** Link Testing Mods - create artificial errors *****/
  1299.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  1300.    gets(dpkerr);
  1301.    if (dpkerr[0] == 's')
  1302.       sscanf(&dpkerr[1], "%d", &xxx);
  1303.    /***** End Link Testing Mods *****/
  1304. #endif   /* LINKTEST */
  1305.  
  1306.    if ( debuglevel > 4 )
  1307.       printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d, buf = %d",
  1308.                type, yyy, xxx, len, xmit);
  1309.  
  1310.    header[0] = '\020';
  1311.    header[4] = (unsigned char) (type << 3);
  1312.  
  1313.    switch (type) {
  1314.  
  1315.       case CLOSE:
  1316.          break;   /* stop protocol */
  1317.  
  1318.       case NAK:
  1319.          header[4] += yyy;
  1320.          break;   /* reject */
  1321.  
  1322.       case SRJ:
  1323.          break;
  1324.  
  1325.       case ACK:
  1326.          header[4] += yyy;
  1327.          break;   /* ack */
  1328.  
  1329.       case INITA:
  1330.       case INITC:
  1331.          header[4] += xmit;
  1332.          break;
  1333.  
  1334.       case INITB:
  1335.          i = MINPKT;
  1336.          while( i < xmit )
  1337.          {
  1338.             header[4] ++;
  1339.             i *= 2;
  1340.          }
  1341.          break;
  1342.  
  1343.       case DATA:
  1344.          header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  1345.          if (len < (short) xmit)      /* Short packet?              */
  1346.             header[4] |= 0x40;/* Count byte handled at higher level */
  1347.  
  1348. #ifdef UDEBUG
  1349.             printmsg(7, "data=|%.*s|", len, data);
  1350. #endif
  1351.          break;
  1352.  
  1353.       default:
  1354.          printmsg(0,"gspack: Invalid packet type %d",type);
  1355.          panic();
  1356.    } /* switch */
  1357.  
  1358. /*--------------------------------------------------------------------*/
  1359. /*    Now we finish up the header.  For data packets, determine       */
  1360. /*    the K number in header[1], which specifies the number of        */
  1361. /*    actual data bytes transmitted as a power of 2; we also          */
  1362. /*    compute a checksum on the data.                                 */
  1363. /*--------------------------------------------------------------------*/
  1364.  
  1365.    if (type == DATA)
  1366.    {
  1367.       header[1] = 1;
  1368.       i = MINPKT;
  1369.       while( i < xmit )
  1370.       {
  1371.          header[1] ++;
  1372.          i *= 2;
  1373.       }
  1374.  
  1375.       if ( i != xmit )        /* Did it come out exact power of 2?   */
  1376.       {
  1377.          printmsg(0,"Packet length error ... %d != %d for K = %d",
  1378.                i, xmit, (int) header[1]);
  1379.          panic();             /* No --> Well, we blew THAT math      */
  1380.       } /* if ( i != xmit ) */
  1381.  
  1382. /*--------------------------------------------------------------------*/
  1383. /*                        Compute the checksum                        */
  1384. /*--------------------------------------------------------------------*/
  1385.  
  1386.       check = checksum(data, xmit);
  1387.       i = header[4]; /* got to do this on PC for ex-or high bits */
  1388.       i &= 0xff;
  1389.       check = (check ^ i) & 0xffff;
  1390.       check = (0xaaaa - check) & 0xffff;
  1391.    }
  1392.    else {
  1393.       header[1] = 9;          /* Control packet size K number (9)    */
  1394.       check = (0xaaaa - header[4]) & 0xffff;
  1395.                               /* Simple checksum for control         */
  1396.    } /* else */
  1397.  
  1398.    header[2] = (unsigned char) (check & 0xff);
  1399.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  1400.    header[5] = (unsigned char)
  1401.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  1402.  
  1403. #ifdef   LINKTEST
  1404.    /***** More Link Testing Mods *****/
  1405.    switch(dpkerr[0]) {
  1406.    case 'e':
  1407.       data[10] = - data[10];
  1408.       break;
  1409.    case 'h':
  1410.       header[5] = - header[5];
  1411.       break;
  1412.    case 'l':
  1413.       return;
  1414.    case 'p':
  1415.       swrite((char *) header, HDRSIZE);
  1416.       if (header[1] != 9)
  1417.          swrite(data, xmit - 3);
  1418.       return;
  1419.    default:
  1420.       break;
  1421.    }
  1422.    /***** End Link Testing Mods *****/
  1423. #endif   /* LINKTEST */
  1424.  
  1425.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  1426.    if (header[1] != 9)
  1427.       swrite(data, xmit);
  1428.  
  1429. } /*gspack*/
  1430.  
  1431.  
  1432. /*
  1433.    g r p a c k
  1434.  
  1435.    Read packet
  1436.  
  1437.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  1438.  
  1439.    ret(type)       ok
  1440.    ret(DCP_EMPTY)  input buf empty
  1441.    ret(DCP_ERROR)  bad header
  1442.  
  1443.    ret(DCP_EMPTY)  lost packet timeout
  1444.    ret(DCP_ERROR)  checksum error
  1445.  
  1446.    NOTE (specifications for sread()):
  1447.  
  1448.    sread(buf, n, timeout)
  1449.       while(TRUE) {
  1450.          if (# of chars available >= n) (without dec internal counter)
  1451.             read n chars into buf (decrement internal char counter)
  1452.             break
  1453.     else
  1454.        if (time > timeout)
  1455.           break;
  1456.       }
  1457.       return(# of chars available)
  1458.  
  1459. */
  1460.  
  1461. static short grpack(short *yyy,
  1462.                   short *xxx,
  1463.                   short *len,
  1464.                   char UUFAR *data,
  1465.                   const short timeout)
  1466. {
  1467.    static short got_hdr  = FALSE;
  1468.    static short received = 0;     /* Bytes already read into buffer */
  1469.    short needed;
  1470.  
  1471.    unsigned short type, check, checkchk, i, total = 0;
  1472.    unsigned char c, c2;
  1473.  
  1474.    time_t start;
  1475.  
  1476.    if (got_hdr)
  1477.       goto get_data;
  1478.  
  1479. /*--------------------------------------------------------------------*/
  1480. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  1481. /*--------------------------------------------------------------------*/
  1482.  
  1483.    start = 0;
  1484.    while (!got_hdr)
  1485.    {
  1486.       unsigned char *psync;
  1487.  
  1488.       needed = HDRSIZE - received;
  1489.       if ( needed > 0 )       /* Have enough bytes for header?       */
  1490.       {                       /* No --> Read as much as we need      */
  1491.          short wait;
  1492.  
  1493.          if ( start == 0 )    /* First pass through data?            */
  1494.          {                    /* Yes --> Set timers up               */
  1495.             start = time(nil(time_t));
  1496.             wait = timeout;
  1497.          } /* if ( start == 0 ) */
  1498.          else {
  1499.             wait = (short) (time(NULL) - start) - timeout;
  1500.             if (wait < 0)     /* Negative timeout?                   */
  1501.                wait = 0;      /* Make it no time out                 */
  1502.          } /* else */
  1503.  
  1504.          if (sread((char *) &grpkt[received], needed, wait ) <
  1505.              (unsigned short) needed )
  1506.                               /* Did we get the needed data?         */
  1507.             return DCP_EMPTY; /* No --> Return to caller             */
  1508.  
  1509.          received += needed;
  1510.       } /* if ( needed < received ) */
  1511.  
  1512. /*--------------------------------------------------------------------*/
  1513. /*            Search for sync character in newly read data            */
  1514. /*--------------------------------------------------------------------*/
  1515.  
  1516. #ifdef UDEBUG
  1517.       printmsg(10,"grpack: Have %d characters after reading %d",
  1518.                received, needed);
  1519. #endif
  1520.  
  1521.       psync = memchr( grpkt, '\020', received );
  1522.       if ( psync == NULL )    /* Did we find the sync character?     */
  1523.          received = 0;        /* No --> Reset to empty buffer        */
  1524.       else if ( psync != grpkt ) /* First character in buffer?       */
  1525.       {                       /* No --> Make it first character      */
  1526.          received -= psync - grpkt;
  1527.          shifts++;
  1528.          memmove( grpkt, psync, received );
  1529.                               /* Shift buffer over                   */
  1530.       } /* else */
  1531.  
  1532. /*--------------------------------------------------------------------*/
  1533. /*    If we have read an entire packet header, then perform a         */
  1534. /*    simple XOR checksum to determine if it is valid.  If we have    */
  1535. /*    a valid checksum, drop out of this search, else drop the        */
  1536. /*    sync character and restart the scan.                            */
  1537. /*--------------------------------------------------------------------*/
  1538.  
  1539.       if ( received >= HDRSIZE )
  1540.       {
  1541.          i = (unsigned short) (grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
  1542.                         grpkt[4] ^ grpkt[5]);
  1543.          i &= 0xff;
  1544.          printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  1545.             grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  1546.  
  1547.          if (i == 0)          /* Good header?                        */
  1548.             got_hdr = TRUE;   /* Yes --> Drop out of loop            */
  1549.          else {               /* No  --> Flag it, continue loop      */
  1550.             badhdr++;
  1551.             printmsg(GDEBUG, "*** bad pkt header ***");
  1552.             memmove( grpkt, &grpkt[ 1 ], --received );
  1553.                               /* Begin scanning for sync character
  1554.                                  with next byte                      */
  1555.          } /* else */
  1556.       } /* if ( received > HDRSIZE ) */
  1557.    } /* while */
  1558.  
  1559. /*--------------------------------------------------------------------*/
  1560. /*                       Handle control packets                       */
  1561. /*--------------------------------------------------------------------*/
  1562.  
  1563.    if (grpkt[1] == 9)
  1564.    {
  1565.       if ( data != NULL )
  1566.          *data = '\0';
  1567.       *len = 0;
  1568.       c = grpkt[4];
  1569.       type = c >> 3;
  1570.       *yyy = c & 0x07;
  1571.       *xxx = 0;
  1572.       check = 0;
  1573.       checkchk = 0;
  1574.       got_hdr = FALSE;
  1575.    }
  1576.  
  1577. /*--------------------------------------------------------------------*/
  1578. /*                        Handle data packets                         */
  1579. /*--------------------------------------------------------------------*/
  1580.    else {
  1581. get_data:
  1582.       if ( data == NULL )
  1583.       {
  1584.          printmsg(0,"grpack: Unexpected data packet!");
  1585.          received = 0;
  1586.          return(DCP_ERROR);
  1587.       }
  1588.  
  1589. /*--------------------------------------------------------------------*/
  1590. /*             Compute the size of the data block desired             */
  1591. /*--------------------------------------------------------------------*/
  1592.  
  1593.       total = 8 * (2 << grpkt[1]);
  1594.       if (total > r_pktsize)  /* Within the defined limits?          */
  1595.       {                       /* No --> Other system has bad header,
  1596.                                  or the header got corrupted         */
  1597.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  1598.             total, (int) grpkt[1]);
  1599.          received = 0;
  1600.          got_hdr = FALSE;
  1601.          return(DCP_ERROR);
  1602.       }
  1603.  
  1604.       needed = total + HDRSIZE - received;
  1605.                                  /* Compute byte required to fill
  1606.                                     data buffer                      */
  1607.  
  1608. /*--------------------------------------------------------------------*/
  1609. /*     If we don't have enough data in the buffer, read some more     */
  1610. /*--------------------------------------------------------------------*/
  1611.  
  1612.       if ((needed > 0) &&
  1613.           (sread((char *) &grpkt[HDRSIZE+total-needed], needed, timeout) <
  1614.            (unsigned short)needed))
  1615.          return(DCP_EMPTY);
  1616.  
  1617.       got_hdr = FALSE;           /* Must re-process header next pass */
  1618.  
  1619. /*--------------------------------------------------------------------*/
  1620. /*              Break packet header into various values               */
  1621. /*--------------------------------------------------------------------*/
  1622.  
  1623.       type = 0;
  1624.       c2 = grpkt[4];
  1625.       c = (unsigned char) (c2 & 0x3f);
  1626.       *xxx = c >> 3;
  1627.       *yyy = c & 0x07;
  1628.       i = grpkt[3];
  1629.       i = (i << 8) & 0xff00;
  1630.       check = grpkt[2];
  1631.       check = i | (check & 0xff);
  1632.       checkchk = checksum( (char *) grpkt + HDRSIZE , total);
  1633.       i = grpkt[4] | 0x80;
  1634.       i &= 0xff;
  1635.       checkchk = 0xaaaa - (checkchk ^ i);
  1636.       checkchk &= 0xffff;
  1637.       if (checkchk != check)
  1638.       {
  1639.          printmsg(4, "*** checksum error ***");
  1640.          memmove( grpkt, grpkt + HDRSIZE, total );
  1641.                               /* Save data so we can scan for sync   */
  1642.          received = total;    /* Note the amount of the data in buf  */
  1643.          return(DCP_ERROR);   /* Return to caller with error         */
  1644.       }
  1645.  
  1646. /*--------------------------------------------------------------------*/
  1647. /*    The checksum is correct, now determine the length of the        */
  1648. /*    data to return.                                                 */
  1649. /*--------------------------------------------------------------------*/
  1650.  
  1651.       *len = total;
  1652.  
  1653.       if (c2 & 0x40)
  1654.       {
  1655.          short ii;
  1656.          if ( grpkt[HDRSIZE] & 0x80 )
  1657.          {
  1658.             ii = (grpkt[HDRSIZE] & 0x7f) + ((grpkt[HDRSIZE+1] & 0xff) << 7);
  1659.             *len -= ii;
  1660.             MEMCPY(data, grpkt + HDRSIZE + 2, *len);
  1661.          }
  1662.          else {
  1663.             ii = (grpkt[HDRSIZE] & 0xff);
  1664.             *len -= ii;
  1665.             MEMCPY(data, grpkt + HDRSIZE + 1, *len);
  1666.          } /* else */
  1667.       }
  1668.       else
  1669.          MEMCPY( data, grpkt + HDRSIZE, *len);
  1670.    } /* else */
  1671.  
  1672. /*--------------------------------------------------------------------*/
  1673. /*           Announce what we got and return to the caller            */
  1674. /*--------------------------------------------------------------------*/
  1675.  
  1676.    received = 0;              /* Returning entire buffer, reset count */
  1677.    printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1678.       type, *yyy, *xxx, *len);
  1679.  
  1680. #ifdef UDEBUG
  1681.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1682.       check, checkchk, total, grpkt + HDRSIZE);
  1683. #endif
  1684.  
  1685.    return(type);
  1686.  
  1687. } /*grpack*/
  1688.  
  1689.  
  1690. /*
  1691.    c h e c k s u m
  1692. */
  1693.  
  1694. static unsigned short checksum(char *data, short len)
  1695. {
  1696.    short i, j;
  1697.    unsigned short tmp, chk1, chk2;
  1698.    chk1 = 0xffff;
  1699.    chk2 = 0;
  1700.    j = len;
  1701.    for (i = 0; i < len; i++) {
  1702.       if (chk1 & 0x8000) {
  1703.          chk1 <<= 1;
  1704.          chk1++;
  1705.       } else {
  1706.          chk1 <<= 1;
  1707.       }
  1708.       tmp = chk1;
  1709.       chk1 += (data[i] & 0xff);
  1710.       chk2 += chk1 ^ j;
  1711.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1712.          chk1 ^= chk2;
  1713.       j--;
  1714.    }
  1715.    return(chk1 & 0xffff);
  1716.  
  1717. } /*checksum*/
  1718.